package com.bristua.mall.wx.biz;

import com.bristua.mall.common.exception.BizException;
import com.bristua.mall.common.utils.HttpUtils;
import com.bristua.mall.common.utils.JsonUtil;
import com.bristua.mall.common.utils.RandomStringGenerator;
import com.bristua.mall.order.dao.TOrderMapper;
import com.bristua.mall.order.model.TOrder;
import com.bristua.mall.user.dao.TUserChargeMapper;
import com.bristua.mall.user.model.TUserCharge;
import com.bristua.mall.wx.enums.WxPayCode;
import com.bristua.mall.wx.model.WXConfig;
import com.bristua.mall.wx.model.condition.WXAppPayOrderParams;
import com.bristua.mall.wx.model.vo.WxAPPSendOrderVO;
import com.bristua.mall.wx.util.RequestHandler;
import com.bristua.mall.wx.util.WXPayConstants;
import com.bristua.mall.wx.util.WXPayUtil;
import io.swagger.models.auth.In;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * Created by Administrator on 2019/4/19.
 */
@Component
public class WxAppPayBiz {
    private static final Logger logger = LoggerFactory.getLogger(WxAppPayBiz.class);

    @Autowired
    private WXConfig wxConfig;

    @Resource
    private TOrderMapper tOrderMapper;

    @Resource
    private TUserChargeMapper tUserChargeMapper;





    public WxAPPSendOrderVO wxAppPay(WXAppPayOrderParams wxAppPayOrderParams) {
        logger.info("==>app支付入参:" + JsonUtil.toJson(wxAppPayOrderParams));
        Map<String, String> data = new HashMap<>();
        data.put("body", wxAppPayOrderParams.getGoodsDesc());
        data.put("out_trade_no", wxAppPayOrderParams.getTradeOrderId());

        if(wxAppPayOrderParams.getAttach().equals("vip")){
            TUserCharge tUserCharge = tUserChargeMapper.selectByPrimaryKey(wxAppPayOrderParams.getTradeOrderId());
            data.put("total_fee",tUserCharge.getChargeAmount());
        }else{
            TOrder tOrder = tOrderMapper.selectByPrimaryKey(wxAppPayOrderParams.getTradeOrderId());
            BigDecimal totalFee = new BigDecimal(tOrder.getOrderPrice()).add(new BigDecimal(tOrder.getFreight()));
            data.put("total_fee",String.valueOf(totalFee.longValue()));
        }

        data.put("spbill_create_ip", wxAppPayOrderParams.getSpbillCreateIp());
        data.put("notify_url", wxConfig.getNotifyUrl());
        String nonce_str = RandomStringGenerator.getRandomStringByLength(32);
        data.put("nonce_str",nonce_str);
        data.put("trade_type", "APP");
        data.put("attach", wxAppPayOrderParams.getAttach());
        data.put("appid", wxConfig.getAppid());
        data.put("mch_id", wxConfig.getMchId());
        data.put("sign_type", WXPayConstants.MD5);
        try {
            data.put("sign", WXPayUtil.generateSignature(data, wxConfig.getKey(), WXPayConstants.SignType.MD5));

            BasicHttpClientConnectionManager connManager = new BasicHttpClientConnectionManager(
                    RegistryBuilder.<ConnectionSocketFactory>create()
                            .register("http", PlainConnectionSocketFactory.getSocketFactory())
                            .register("https", SSLConnectionSocketFactory.getSocketFactory())
                            .build(),
                    null,
                    null,
                    null
            );

            HttpClient httpClient = HttpClientBuilder.create()
                    .setConnectionManager(connManager)
                    .build();

            String url = wxConfig.getAppPayUrl();
            HttpPost httpPost = new HttpPost(url);

            RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(6000).setConnectTimeout(8000).build();
            httpPost.setConfig(requestConfig);

            String reqBody = WXPayUtil.mapToXml(data);
            logger.debug("reqBody==>===={}", reqBody);


            StringEntity postEntity = new StringEntity(reqBody, "UTF-8");
            httpPost.addHeader("Content-Type", "text/xml");
            httpPost.addHeader("User-Agent", "wxpay sdk java v1.0 " + wxConfig.getMchId());  // TODO: 很重要，用来检测 sdk 的使用情况，要不要加上商户信息？
            httpPost.setEntity(postEntity);

            HttpResponse httpResponse = httpClient.execute(httpPost);
            HttpEntity httpEntity = httpResponse.getEntity();
            String s = EntityUtils.toString(httpEntity, "UTF-8");
            Map<String, String> respData = WXPayUtil.xmlToMap(s);
            logger.info("微信下单返回参数：" + JsonUtil.toJson(respData));
            String RETURN_CODE = "return_code";
            String return_code;
            if (respData.containsKey(RETURN_CODE)) {
                return_code = respData.get(RETURN_CODE);
            } else {
                throw new Exception(String.format("No `return_code` in XML: %s", s));
            }


            if (return_code.equals(WXPayConstants.FAIL)) {
                throw new BizException(WxPayCode.WX_APP_SEND_ORDER_FAIL.getCode(),WxPayCode.WX_APP_SEND_ORDER_FAIL.getMsg());
            } else if (return_code.equals(WXPayConstants.SUCCESS)) {
                if (this.isResponseSignatureValid(respData)) {
                    WxAPPSendOrderVO wxAPPSendOrderVO = new WxAPPSendOrderVO();
                    wxAPPSendOrderVO.setAppid(wxConfig.getAppid());
                    wxAPPSendOrderVO.setNoncestr(nonce_str);
                    String packageApp = "Sign=WXPay";
                    wxAPPSendOrderVO.setPackages(packageApp);
                    wxAPPSendOrderVO.setPartnerid(wxConfig.getMchId());
                    wxAPPSendOrderVO.setPrepayid(respData.get("prepay_id"));
                    String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
                    wxAPPSendOrderVO.setTimestamp(timestamp);
                    RequestHandler reqHandlerApp = new RequestHandler(null, null);
                    reqHandlerApp.init(wxConfig.getAppid(), wxConfig.getKey());
                    SortedMap<String, String> finalpackageApp = new TreeMap<String, String>();

                    finalpackageApp.put("appid", wxConfig.getAppid());
                    finalpackageApp.put("partnerid", wxConfig.getMchId());
                    finalpackageApp.put("prepayid", respData.get("prepay_id"));
                    finalpackageApp.put("package", packageApp);
                    finalpackageApp.put("noncestr", nonce_str);
                    finalpackageApp.put("timestamp", timestamp);
                    String finalsignApp = reqHandlerApp.createSign(finalpackageApp);
                    wxAPPSendOrderVO.setSign(finalsignApp);
                    return wxAPPSendOrderVO;
                } else {
                    throw new Exception(String.format("Invalid sign value in XML: %s", s));
                }
            } else {
                throw new Exception(String.format("return_code value %s is invalid in XML: %s", return_code, s));
            }

        } catch (Exception ex) {
            logger.error("==>微信统一下单",ex);
        }
        return null;
    }

    public boolean isResponseSignatureValid(Map<String, String> reqData) throws Exception {
        // 返回数据的签名方式和请求中给定的签名方式是一致的
        return WXPayUtil.isSignatureValid(reqData, wxConfig.getKey(), WXPayConstants.SignType.MD5);
    }
}
